#pragma once
#include <iostream>
#include <cstring>
#include <sys/types.h>
#include <string>
#include <memory>

#include "socket.hpp"
#include "log.hpp"
#include "EpollIn.hpp"

namespace EpollServer
{
    class Epoll
    {
        static const int defaultfd = -1;
        static const int cap = 64;//_event的初始容量
        static const int ADD = EPOLL_CTL_ADD;
        static const int MOD = EPOLL_CTL_MOD;
        static const int DEL = EPOLL_CTL_DEL;
        
        static const int IN = EPOLLIN;
        static const int OUT = EPOLLOUT;
        static const int INIT = 0;
        static const int Time = 3000;

    public:
        Epoll(uint16_t port)
            : _maxcap(cap)
            , _listenfd(new SocketInter::SockIn(port))
            , _epoll(new EpollIn::Epoll)
            , _event(new epoll_event[_maxcap])
        {
           
            for(int i = 0;i < _maxcap;i++)
            {
                _event[i].events = INIT;
                _event[i].data.fd = defaultfd;
            }
        }
        ~Epoll(){delete _event;}
        void Init()
        {
            _listenfd->InitSockaddr();
            _listenfd->Socket();
            _listenfd->Bind();
            _listenfd->Listen();
        }
        void run()
        {
            int listenfd = _listenfd->listenfd();
           
            _event[0].events = IN;
            _event[0].data.fd = listenfd;
            _epoll->EpollCtl(ADD,listenfd,_event[0]);
            while (true)
            {
                int timeout = Time;
                int n = _epoll->EpollWait(_event,_maxcap,timeout);
                switch (n)
                {
                case 0:
                    mylog::log(Info,"epoll_wait 超时");
                    break;
                case -1:
                    mylog::log(Error,"epoll_wait 出错,errno:%d,strerror:%s",errno,strerror(errno));
                    break;
                default:
                    Distribution();
                }
            }
        }

        void Distribution()
        {
            for (int i = 0; i < _maxcap; i++)
            {
                int fd = _event[i].data.fd;
                if (fd == defaultfd)
                    continue;
                if (_event[i].events & IN)
                {
                    if (fd == _listenfd->listenfd())
                    {
                        GetLink();
                    }
                    else
                    {
                        EventReady(fd, i);
                    }
                }
            }
        }

        void GetLink() // 获取连接
        {
            int sock = _listenfd->Accept();
            setnonblock(sock);
            std::string ip = _listenfd->GetClientip();
            uint16_t port = _listenfd->GetClientport();
            mylog::log(Info, "客户端ip:%s,端口号:%d,连接成功", ip.c_str(), port);
            bool fill = true;
            for (int i = 0; i < cap; i++)
            {
                if (_event[i].data.fd == defaultfd)
                {
                    _event[i].events = IN;
                    _event[i].data.fd = sock;
                    _epoll->EpollCtl(ADD,sock,_event[i]);
                    fill = false;
                    break;
                }
            }

            if (fill)
            {
                int pos = _maxcap;
                _maxcap *= 2;
                epoll_event * tmp = new epoll_event[_maxcap];
                if(tmp)
                {
                    for(int i = 0;i < _maxcap;i++)
                    {
                        if(i < pos) tmp[i] = _event[i];
                        tmp[i].events = INIT;
                        tmp[i].data.fd = defaultfd; 
                    }
                    delete _event;
                    _event = tmp;
                    _event[pos].events = IN;
                    _event[pos].data.fd = sock;
                    _epoll->EpollCtl(ADD,sock,_event[pos]);
                    mylog::log(Info, "扩容成功,当前容量:%d",_maxcap);
                }
                else
                {
                    mylog::log(Warning, "扩容失败");
                    close(sock);
                }
            }
        }

        void EventReady(int fd, int pos) // 事件就绪
        {
            char bufstr[1024];
            
            int n = read(fd, bufstr, sizeof(bufstr) - 1);
            bool exitfd = false;
            if (n > 0)
            {
                bufstr[n] = 0;
                std::cout << bufstr << std::endl;
            }
            else if (n == 0)
            {
                exitfd = true;
                mylog::log(Info,"写端退出");
            }
            else
            {
                if (errno = EWOULDBLOCK)
                {
                    mylog::log(Info,"缓存为空");
                }
                else
                {
                    mylog::log(Error,"读取失败");
                    exitfd = true;
                }
            }

            if(exitfd)
            {
                _epoll->EpollCtl(DEL,fd,_event[pos]);
                _event[pos].data.fd = defaultfd;
                _event[pos].events = INIT;
                close(fd);
                exitfd = false;
            }
        }

        void setnonblock(int fd)
        {
            int n = fcntl(fd, F_GETFD);
            if (n < 0)
            {
                perror("fcntl");
                //exit(1);
            }
            if (fcntl(fd, F_SETFL, n | O_NONBLOCK) == 0)
            {
                std::cout << "fd : " << fd << "设置非阻塞成功" << std::endl;
            }
        }

    private:
        size_t _maxcap;
        std::shared_ptr<SocketInter::SockIn> _listenfd;
        std::shared_ptr<EpollIn::Epoll> _epoll;
        epoll_event *_event;
        
    };
}